// 引入express模块
const express = require('express')
// 引入fs模块
const fs = require('fs')
// 引入path模块
const { resolve } = require('path')
// 引入管理者数据模型
const adminModel = require('../db/modules/adminModule')
// 引入广告数据模型
const advModel = require('../db/modules/advModule')
// 引入自己写的工具函数(生成token的函数)
const jwt = require('../utils/jwtManger')
// 创建路由表(空表)
const router = express.Router()
// 🎠 定义一个验证token的中间件，广告的增删改查都要先校验token
async function VerToken(req, res, next) {
    // 😡 注意，req.fields只能应用在post请求上边，所以，当这个中间件用在grt请求上时，就取不到id的值
    // 😡 因此，要处理一下中间件的兼容性
    let id = req.fields.id || req.query.id
    // 从请求头中获取token数据
    let token = req.get('token')
    // 验证是否存在token，若不存在则返回失败
    if (!token) return res.send({ "code": 0, "msg": "token失效，请重新登录" })
    // 若token存在，和数据库中的token进行校验，若不存在则返回失败
    // findOne的返回值： 如果成功 返回一条数据文档 如果失败 返回值为null
    let admin = await adminModel.findOne({ _id: id, token })
    if (!admin) return res.send({ "code": 0, "msg": "token失效，请重新登录" })
    // 若token存在并且token和数据库中的一致，验证有效期
    // 当前的时间戳
    let currentTime = Date.now()
    // token中存储的 (创建token的时间戳 + 有效期)的时间戳
    let liveTime = jwt.decodeToken(token).expires
    // 如果过期，则失效，返回失败
    if (currentTime >= liveTime) return res.send({ "code": 0, "msg": "token失效，请重新登录" })
    // 若满足上述三点if条件，则验证通过
    // res.send({"code":1,"msg":"token通过验证"})
    next()
}

// ✨ 添加广告接口 http://localhost:8080/addAdv
// 中间件VerToken要添加到路径和回调函数之前
router.post('/addAdv', VerToken, async (req, res) => {
    // 首先从请求体中获取传过来的参数
    let { advTitle, advCate, advLink } = req.fields
    // 解构赋值
    let { files } = req.files
    //
    const filename = files.path.replace('public\\uploadDir\\', '')
    const advImg = 'http://localhost:8080/uploadDir/' + filename
    await advModel.create({ advTitle, advCate, advLink, advImg })
    const advs = await advModel.find()
    res.send({ "code": 1, "msg": '添加成功', advs })
})

// ✨删除广告接口 http://localhost:8080/removeAdv
router.post('/removeAdv', VerToken, async (req, res) => {
    // 1.首先从前端发送的请求体中获取广告的Id
    const { advId } = req.fields

    // 5.在删除广告之前，通过广告的ID查询到该条广告的文件名
    const adv = await advModel.findOne({ '_id': advId })

    // 6.把http://localhost:8080/uploadDir/upload_cac4bca7f6e876c28f3eac07294c4d3b.jpg 替换为
    // upload_cac4bca7f6e876c28f3eac07294c4d3b.jpg
    const filename = adv.advImg.replace('http://localhost:8080/uploadDir/', '')

    // 2.通过广告的ID查询数据库
    await advModel.deleteOne({ '_id': advId })

    // 7.手动删除当前这条数据所对应的图片
    // path为将要删除的图片的绝对路径
    const path = resolve(__dirname, '../public/uploadDir', filename)

    // 8.一般在服务器上删除文件使用同步 unlinkSync 异步为 unlink
    fs.unlinkSync(path)

    // 3.并从数据库中拿取最新的数据
    const advs = await advModel.find()

    // 4.将最新的数据返回给客户端
    res.send({ 'code': 1, 'msg': '删除成功', advs })
})

// ✨修改/更新广告接口 http://localhost:8080/updataAdv
router.post('/updataAdv', VerToken, async (req, res) => {
    // 首先从请求体中获取传过来的参数
    let { advTitle, advCate, advLink, advId } = req.fields
    // 解构赋值
    let { files } = req.files
    // 判断是否修改广告的图片
    // 修改图片
    if (files.size) {
        // 🐷 删除服务器中的图片
        // 根据广告ID获取要更改的广告数据
        const adv = await advModel.findOne({ _id: advId })
        // 将上述广告的advImg替换为文件名
        const oldfilename = adv.advImg.replace('http://localhost:8080/uploadDir/', '')
        // 拼接出 服务器静态资源 要更换的文件的路径
        const path = resolve(__dirname, '../public/uploadDir', oldfilename)
        // 删除要更换的图片
        fs.unlinkSync(path)
        // 🐷 修改数据库中的图片
        // 去掉formidable中间件为图片加的前缀
        const newfilename = files.path.replace('public\\uploadDir\\', '')
        // 拼接新的图片路径
        const advImg = 'http://localhost:8080/uploadDir/' + newfilename
        // 操作数据库，修改
        await advModel.updateOne({ _id: advId }, { $set: { advTitle, advCate, advLink, advImg, updateAdvDate: Date.now() } })
    } else {
        // 不修改图片
        // 空白文件的文件名
        const filename = files.path.replace('public\\uploadDir\\', '')
        // 删除空白文件
        fs.unlinkSync(resolve(__dirname, '../public/uploadDir', filename))

        await advModel.updateOne(
            { _id: advId },
            { $set: { advTitle, advCate, advLink, updateAdvDate: Date.now() } }
        )
    }
    // 重新获取最新的数据
    const advs = await advModel.find()
    res.send({ 'code': 1, 'msg': '修改成功', advs })
})

// ✨查询广告接口 http://localhost:8080/findAdv
router.get('/findAdv', VerToken, async (req, res) => {
    // 如果因为某些原因导致advModel.find()是失败的状态，所以这里用try/catch来捕获一下
    try {
        // 操作广告数据模型,find方法返回的是一个数组，数组里边包含对象，是一条一条的数据
        const result = await advModel.find()
        // 将结果响应回去
        res.send({ 'code': 1, 'msg': '获取成功', "data": result })
    } catch (error) {
        res.send({ 'code': 0, 'msg': '获取失败' })
    }
})

// ✨查询单条广告的接口 http://localhost:8080/GetOneAdv
router.get('/GetOneAdv', VerToken, async (req, res) => {
    const { advId } = req.query
    const adv = await advModel.findOne({ _id: advId })
    res.send({ code: 1, msg: '查询成功', adv })
})

module.exports = router
